package org.travelfusion.xmlclient.ri.xobject.misc;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import com.google.gwt.user.client.rpc.IsSerializable;

/**
 * A wrapper representing container holding information of given supplier configuration and its
 * features
 * @author Veselin Andreev (veselin.andreev@gmail.com)
 * @category PRIVILEGED_ACCESS
 */
public class XAffiliateSupplier implements Comparable<XAffiliateSupplier>, Serializable, IsSerializable {

	private static final long serialVersionUID = 8210386802441014141L;

	/**
	 * A enumeration wrapper representing the available supplier implementation types
	 */
	public static enum ImplementationType implements Serializable, IsSerializable {
		UNKNOWN, ROUTE_ONLY, SEARCH_ONLY, BOOK_ONLY
	}

	/**
	 * A enumeration wrapper representing the available supplier modes
	 */
	public static enum Mode implements Serializable, IsSerializable {
		UNKNOWN, PLANE, HOTEL, CAR, TRAIN, FERRY, PREPACKAGED
	}

	/**
	 * A enumeration wrapper representing the possible OpenJaw implementation given supplier can
	 * support
	 */
	public static enum OpenJawSupport implements Serializable, IsSerializable {
		/** Not Supported */
		NOT_SUPPORTED,
		/** Supports OpenJaw */
		SUPPORTED,
		/** Supports OpenJaw with city search */
		SUPPORTED_WITH_CITY_SEARCH
	}

	/**
	 * A enumeration container representing the available payment types given supplier can support
	 */
	public static interface PaymentSupport extends Serializable, IsSerializable {

		/** The payment support is unknown. Used for non plane mode suppliers */
		int UNKNOWN = 0;
		/** Payments through credit card */
		int CREDIT_CARD = 1;
		/** Payments through agency account */
		int AGENCY_PAYMENT = 2;
		/**
		 * Payments through TravelFusion Credit Settlement Plan. For more information call/email
		 * TravelFusion Operations Team
		 */
		int TRAVELFUSION_CREDIT_SETTLEMENT_PLAN = 4;
	}

	/**
	 * A enumeration container representing the supplier integration types.
	 */
	public static enum IntegrationType implements Serializable, IsSerializable {
		/** Not specified */
		UNKNOWN,
		/** XML feed link */
		XML,
		/** Screen Scraping */
		SCREENSCRAPE
	}

	/**
	 * A enumeration container representing the supplier referral tracker type
	 */
	public static enum ReferralTrackerType implements Serializable, IsSerializable {
		UNKNOWN,
		/** Third party tracker site */
		THIRD_PARTY_TRACKER,
		/** Supplier own tracking system */
		SUPPLIER_OWN_TRACKER,
		/** TravelFusion internal tracking system */
		TRAVELFUSION_TRACKER
	}

	/**
	 * A wrapper representing the referral tracker system information
	 */
	public static class ReferralTracker implements Serializable, IsSerializable {

		private static final long serialVersionUID = 4397953309517111631L;
		/** the referral tracker name */
		private String name = null;
		/** the referral tracker type */
		private ReferralTrackerType type = ReferralTrackerType.UNKNOWN;
		/** a flag indicating whether referral tracking system support child ids */
		private boolean supportsChildIds = false;

		/**
		 * Sets the referral tracker name
		 * @param name the tracker name
		 * @throws NullPointerException
		 */
		public void setTrackerName(String name) throws NullPointerException {
			if (name == null) {
				throw new NullPointerException();
			}
			if (name.endsWith("Tracker")) {
				name = name.substring(0, name.lastIndexOf("Tracker"));
			}
			this.name = new String(name);
		}

		/**
		 * Sets the referral tracker type
		 * @param type
		 * @throws NullPointerException
		 */
		public void setTrackerType(ReferralTrackerType type) throws NullPointerException {
			if (type == null) {
				throw new NullPointerException();
			}
			this.type = type;
		}

		/**
		 * Sets whether or not the referral tracking system supports child ids
		 * @param state
		 */
		public void setChildIdsSupport(boolean state) {
			supportsChildIds = state;
		}

		/**
		 * Gets the name of the referral tracking system
		 * @return the name of the referral tracking system
		 */
		public String getName() {
			return name;
		}

		/**
		 * Gets the referral tracker type
		 * @return the referral tracker type, otherwise {@code null} if such not given
		 */
		public ReferralTrackerType getType() {
			return type;
		}

		/**
		 * Checks whether or not this referral tracker system supports child ids
		 * @return true if child ids are supported by this referral tracker, otherwise {@code false}
		 */
		public boolean isChildIdsSupported() {
			return supportsChildIds;
		}
	}

	/**
	 * A enumeration wrapper representing given supplier feature support type
	 */
	public static enum FeatureSupportType implements Serializable, IsSerializable {
		/** Undefined feature support type */
		UNKNOWN,
		/** Feature is supported per passenger basis */
		PER_PASSENGER,
		/** Feature is supported per booking basis (for the entire booking) */
		PER_BOOKING,
	}

	/**
	 * A wrapper representing given supplier feature selling point information
	 */
	public static class FeatureSellingPointInfo implements Serializable, IsSerializable {

		private static final long serialVersionUID = -5184364509220523029L;
		/** the selling point title */
		private String title;
		/** the selling point short description */
		private String description;

		/**
		 * Constructor
		 * @throws NullPointerException
		 */
		public FeatureSellingPointInfo() throws NullPointerException {
			title = null;
			description = null;
		}

		/**
		 * Constructor
		 * @param title
		 * @param description
		 * @throws NullPointerException
		 */
		public FeatureSellingPointInfo(String title, String description) throws NullPointerException {
			if (title == null || description == null) {
				throw new NullPointerException();
			}
			this.title = new String(title);
			this.description = new String(description);
		}

		/**
		 * Gets the title of the selling point
		 * @return the title of this selling point
		 */
		public final String getTitle() {
			return title;
		}

		/**
		 * Gets the selling point short description
		 * @return a short description information of this selling point
		 */
		public final String getDescription() {
			return description;
		}
	}

	/**
	 * A wrapper representing single supplier feature
	 */
	public static class Feature implements Serializable, IsSerializable {

		private static final long serialVersionUID = -500336982538259837L;
		/** the name of the feature */
		private String name;
		/** the display name of the feature */
		private String displayName;
		/** a flag indicating whether or not the display name can change for different journeys */
		private boolean displayNameIsDynamic = false;
		/** a flag indicating whether or not the feature is supported for all journeys or partially */
		private boolean isDynamic = false;
		/** a flag indicating the feature support type */
		private FeatureSupportType supportType = FeatureSupportType.UNKNOWN;
		/** the feature selling point information */
		private FeatureSellingPointInfo sellingPoint = null;

		/**
		 * Sets the feature name
		 * @param name
		 * @throws NullPointerException
		 */
		public void setName(String name) throws NullPointerException {
			if (name == null) {
				throw new NullPointerException();
			}
			this.name = new String(name);
		}

		/**
		 * Sets the display name of this feature
		 * @param displayName
		 * @throws NullPointerException
		 */
		public void setDisplayName(String displayName) throws NullPointerException {
			if (displayName == null) {
				throw new NullPointerException();
			}
			this.displayName = new String(displayName);
		}

		/**
		 * Sets the display name customisable state
		 * @param state
		 */
		public void setDisplayNameCustomisable(boolean state) {
			displayNameIsDynamic = state;
		}

		/**
		 * Sets the feature as dynamic
		 * @param state
		 */
		public void setDynamic(boolean state) {
			isDynamic = state;
		}

		/**
		 * Sets the feature support type
		 * @param supportType
		 * @throws NullPointerException
		 */
		public void setSupportType(FeatureSupportType supportType) throws NullPointerException {
			if (supportType == null) {
				throw new NullPointerException();
			}
			this.supportType = supportType;
		}

		/**
		 * Sets the selling point information for this feature
		 * @param sellingPoint
		 * @throws NullPointerException
		 */
		public void setSellingPoint(FeatureSellingPointInfo sellingPoint) throws NullPointerException {
			if (sellingPoint == null) {
				throw new NullPointerException();
			}
			this.sellingPoint = sellingPoint;
		}

		/**
		 * Clears the selling point information from this feature
		 */
		public void clearSellingPoint() {
			this.sellingPoint = null;
		}

		/**
		 * Gets the name of the feature
		 * @return the name of the feature
		 */
		public String getName() {
			return name;
		}

		/**
		 * Gets the display name of the feature
		 * @return short display name of the feature
		 */
		public String getDisplayName() {
			return displayName;
		}

		/**
		 * Checks whether or not the display name can change per journey
		 * @return true if display name is customisable, otherwise {@code false}
		 */
		public boolean isDisplayNameCustomisable() {
			return displayNameIsDynamic;
		}

		/**
		 * Checks whether or not the feature is available per journey basis
		 * @return true if the feature is dynamic, otherwise {@code false}
		 */
		public boolean isDynamic() {
			return isDynamic;
		}

		/**
		 * Gets the feature support type
		 * @return the feature support type
		 */
		public FeatureSupportType getType() {
			return supportType;
		}

		/**
		 * Gets the feature selling point information
		 * @return the feature selling point information, otherwise {@code null}
		 */
		public FeatureSellingPointInfo getSellingPoint() {
			return sellingPoint;
		}
	}

	/** the name of the supplier */
	private String name;
	/** the vendor name of the supplier */
	private String vendorName;
	/** the family name this supplier is part of */
	private String family = null;
	/** the WebSite URL of this supplier */
	private String websiteUrl;
	/** the mode of the supplier */
	private Mode mode = Mode.UNKNOWN;
	/** the implementation type of the supplier */
	private ImplementationType type = ImplementationType.UNKNOWN;
	/** a flag indicating whether the supplier is enabled */
	private boolean isEnabled = false;
	/** a flag indicating whether the supplier is a b2b channel */
	private boolean isB2bChannel = false;
	/** a flag indicating whether the supplier is visible */
	private boolean isVisible = true;
	/** a flag indicating whether the supplier uses as base another supplier integration */
	private boolean isExtension = false;
	/** a flag indicating the OpenJaw support this supplier has */
	private OpenJawSupport openJaw = OpenJawSupport.NOT_SUPPORTED;
	/** a flag indicating the supported payment types by this supplier */
	private int paymentSupport = PaymentSupport.UNKNOWN;
	/** a flag indicating the supplier integration type */
	private IntegrationType integrationType = IntegrationType.UNKNOWN;
	/** a list of two letter drop-in language codes this supplier supports */
	private List<String> dropInLanguages = new ArrayList<String>();
	/** a list of referral tracker clients this supplier supports */
	private List<String> trackerClients = new ArrayList<String>();
	/** the referral tracker system this supplier use */
	private ReferralTracker tracker = null;
	/** a list of features this supplier supports */
	private List<Feature> features = new ArrayList<Feature>();

	/**
	 * Sets the name of the supplier
	 * @param name
	 * @throws NullPointerException
	 */
	public void setName(String name) throws NullPointerException {
		if (name == null) {
			throw new NullPointerException();
		}
		this.name = new String(name);
	}

	/**
	 * Sets the vendor name of the supplier
	 * @param name
	 * @throws NullPointerException
	 */
	public void setVendorName(String name) throws NullPointerException {
		if (name == null) {
			throw new NullPointerException();
		}
		vendorName = new String(name);
	}

	/**
	 * Sets the family name this supplier is part of
	 * @param familyName
	 * @throws NullPointerException
	 */
	public void setFamilyName(String familyName) throws NullPointerException {
		if (familyName == null) {
			throw new NullPointerException();
		}
		family = new String(familyName);
	}

	/**
	 * Sets the WebSite URL of this supplier
	 * @param url
	 * @throws NullPointerException
	 */
	public void setWebsiteUrl(String url) throws NullPointerException {
		if (url == null) {
			throw new NullPointerException();
		}
		websiteUrl = new String(url);
	}

	/**
	 * Sets the mode type of this supplier
	 * @param mode
	 * @throws NullPointerException
	 */
	public void setMode(Mode mode) throws NullPointerException {
		if (mode == null) {
			throw new NullPointerException();
		}
		this.mode = mode;
	}

	/**
	 * Sets the supplier implementation type
	 * @param type
	 * @throws NullPointerException
	 */
	public void setType(ImplementationType type) throws NullPointerException {
		if (type == null) {
			throw new NullPointerException();
		}
		this.type = type;
	}

	/**
	 * Sets the supplier b2b channel state
	 * @param state
	 */
	public void setB2bChannel(boolean state) {
		isB2bChannel = state;
	}

	/**
	 * Sets the supplier status state
	 * @param state
	 */
	public void setEnabled(boolean state) {
		isEnabled = state;
	}

	/**
	 * Sets the supplier visibility sate
	 * @param state
	 */
	public void setVisible(boolean state) {
		isVisible = state;
	}

	/**
	 * Sets the supplier extension state
	 * @param state
	 */
	public void setExtension(boolean state) {
		isExtension = state;
	}

	/**
	 * Sets the OpenJaw support this supplier has
	 * @param support
	 * @throws NullPointerException
	 */
	public void setOpenJaw(OpenJawSupport support) throws NullPointerException {
		if (support == null) {
			throw new NullPointerException();
		}
		openJaw = support;
	}

	/**
	 * Sets the supplier payment types this supplier supports
	 * @param support
	 * @throws IllegalArgumentException
	 */
	public void setPaymentSupports(int type) throws IllegalArgumentException {
		if (type < 0) {
			throw new IllegalArgumentException("Illegal supplier payment support (" + type + ")");
		}
		paymentSupport = type;
	}

	/**
	 * Adds given payment support type to the ones already applied for this supplier
	 * @param type
	 * @throws IllegalArgumentException
	 */
	public void addPaymentSupport(int type) throws IllegalArgumentException {
		if (type < 1) {
			throw new IllegalArgumentException("Illegal supplier payment support (" + type + ")");
		}
		paymentSupport |= type;
	}

	/**
	 * Checks whether the given payment type is supported by this supplier
	 * @param type
	 * @return true if the payment type is supported, otherwise {@code false}
	 * @throws IllegalArgumentException
	 */
	public boolean hasPaymentSupport(int type) throws IllegalArgumentException {
		if (type < 1) {
			throw new IllegalArgumentException("Illegal supplier payment support type (" + type + ")");
		}
		return (paymentSupport & type) > 0;
	}

	/**
	 * Sets the integration type of this supplier
	 * @param type
	 * @throws NullPointerException
	 */
	public void setIntegrationType(IntegrationType type) throws NullPointerException {
		if (type == null) {
			throw new NullPointerException();
		}
		integrationType = type;
	}

	/**
	 * Parses the integration type from given string representation input
	 * @param type
	 * @throws NullPointerException
	 */
	public void parseIntegrationType(String type) throws NullPointerException {
		if (type == null) {
			throw new NullPointerException();
		}
		/** Different variations exists, we need the GENERIC ones only */
		if (type.startsWith("XML")) {
			integrationType = IntegrationType.XML;
		} else if (type.startsWith("HTML")) {
			integrationType = IntegrationType.SCREENSCRAPE;
		} else {
			integrationType = IntegrationType.UNKNOWN;
		}
	}

	/**
	 * Sets the referral tracker system this supplier uses
	 * @param tracker
	 * @throws NullPointerException
	 */
	public void setTracker(ReferralTracker tracker) throws NullPointerException {
		if (tracker == null) {
			throw new NullPointerException();
		}
		this.tracker = tracker;
	}

	/**
	 * Clears the referral tracker system information this supplier uses
	 */
	public void clearTracker() {
		this.tracker = null;
	}

	/**
	 * Gets the name of the supplier
	 * @return the name of the supplier
	 */
	public String getName() {
		return name;
	}

	/**
	 * Gets the vendor name of the supplier
	 * @return the vendor name of the supplier
	 */
	public String getVendorName() {
		return vendorName;
	}

	/**
	 * Checks whether or not the supplier is part of family
	 * @return true if the supplier is part of a family
	 */
	public boolean isPartOfFamily() {
		return family != null;
	}

	/**
	 * Gets the family name this supplier is part of
	 * @return the family name, otherwise {@code null}
	 */
	public String getFamily() {
		return family;
	}

	/**
	 * Gets the WebSite URL of this supplier
	 * @return the URL, otherwise {@code null}
	 */
	public String getWebsiteUrl() {
		return websiteUrl;
	}

	/**
	 * Gets the mode type of this supplier
	 * @return the mode type of this supplier
	 */
	public Mode getMode() {
		return mode;
	}

	/**
	 * Gets the implementation type of this supplier
	 * @return the implementation type of this supplier
	 */
	public ImplementationType getType() {
		return type;
	}

	/**
	 * Checks whether or not the supplier is enabled
	 * @return true if the supplier is enabled, otherwise {@code false}
	 */
	public boolean isEnabled() {
		return isEnabled;
	}

	/**
	 * Checks whether or not the supplier is a b2b channel
	 * @return true if the supplier is a b2b channel, otherwise {@code false}
	 */
	public boolean isB2bChannel() {
		return isB2bChannel;
	}

	/**
	 * Checks whether or not the supplier is visible
	 * @return true if the supplier is visible, otherwise {@code false}
	 */
	public boolean isVisible() {
		return isVisible;
	}

	/**
	 * Checks whether or not this supplier uses as base another supplier integration
	 * @return true if this supplier is extension, otherwise {@code false}
	 */
	public boolean isExtension() {
		return isExtension;
	}

	/**
	 * Gets the OpenJaw support this supplier has
	 * @return the OpenJaw support this support has
	 */
	public OpenJawSupport getOpenJaw() {
		return openJaw;
	}

	/**
	 * Gets the supplier integration type
	 * @return the supplier integration type
	 */
	public IntegrationType getIntegrationType() {
		return integrationType;
	}

	/**
	 * Gets the list of drop-in languages supplier supports
	 * @return the list of drop-in languages this supplier supports
	 */
	public List<String> getDropInLanguages() {
		return dropInLanguages;
	}

	/**
	 * Gets a list of referral tracker clients this supplier has
	 * @return the list of referral tracker clients this supplier has
	 */
	public List<String> getTrackerClients() {
		return trackerClients;
	}

	/**
	 * Gets the referral tracker system information this supplier uses
	 * @return the referral tracker system information this supplier uses, otherwise {@code null}
	 */
	public ReferralTracker getTracker() {
		return tracker;
	}

	/**
	 * Gets the list of features this supplier supports
	 * @return the list of features this supplier supports
	 */
	public List<Feature> getFeatures() {
		return features;
	}

	@Override
	public int compareTo(XAffiliateSupplier supplier) {
		if (name == null) {
			return 1;
		} else if (supplier == null || supplier.name == null) {
			return -1;
		} else {
			return name.compareTo(supplier.name);
		}
	}
}